import { parseTime } from '../../src/utils'

// 外部的工具函数
function get_display_name(item, str) {
  if (str) {
    const str2 = '`' + str.replace(/{/g, '{item.') + '`'

    // eslint-disable-next-line no-eval
    return eval(str2)
  }

  return ''
}

// 外部的工具函数
function get_expression_value(item, str) {
  if (str) {
    const str2 = str.replace(/\$/g, 'item.')

    // eslint-disable-next-line no-eval
    return eval(str2)
  }

  return ''
}

class BaseModel {
  constructor(model, options) {
    const { Models, env, session, metadata = {}, records = [] } = options
    this.Models = Models
    this.model = model
    this.metadata = metadata
    this.records = records
    this.env = env
    this.session = session
  }

  // 非计算列 处理
  // date 字段格式化
  // selection 字段 补充 name
  // 这些基础字段 是为后续的简单计算列做准备的
  _update_value_for_raw_fields(fields = {}, rec0) {
    const rec = { ...rec0 }
    const metadata = this.metadata || {}
    Object.keys(metadata).forEach(item => {
      const meta = metadata[item]
      if (!meta) {
        //
      } else if (meta.display) {
        //
      } else if (meta.expression) {
        //
      } else if (meta.related) {
        //
      } else if (meta.compute) {
        //
      } else if (meta.type === 'date') {
        rec[item] = rec[item] ? parseTime(rec[item], '{y}-{m}-{d}') : rec[item]
      } else if (meta.type === 'selection') {
        const key_value = rec[item]
        rec[item] = key_value
        const new_values = meta.selection.filter(it => key_value === it[0])
        const new_value =
          new_values && new_values[0] ? new_values[0] : [key_value, key_value]
        rec[`${item}__name`] = new_value[1]
      } else {
        // records 中没定义的字段, 根据元数据 补充, 这里可以设置默认值
        const sss = rec[item]
        rec[item] = sss
      }
    })

    return rec
  }

  // 1 处理计算列
  // 11 display 和 expression 是简单的计算, 根据已有的其他列做处理
  // 12 related 是 根据 m2o 字段的值, 调取 browse 函数 取相关列
  // 13 compute 有装饰器函数指明依赖的列, 调取 browse 函数 取相关列进行计算
  //   若不用装饰器指明依赖的列, 则必须是已知列
  // 2 处理 o2m 和 m2m 列. 这两种字段, 看作是计算列. 查询时做计算
  // 21 o2m 字段, 直接在子表中 过滤查找
  // 22 m2m 字段, 直接在关联表中 过滤查找
  _update_value_for_compute(fields, rec0, no_recursion) {
    const rec = { ...rec0 }
    const metadata = this.metadata || {}
    Object.keys(metadata).forEach(item => {
      const meta = metadata[item]
      if (!meta) {
        //
      } else if (meta.display) {
        rec[item] = get_display_name(rec, meta.display)
      } else if (meta.expression) {
        rec[item] = get_expression_value(rec, meta.expression)
      } else if (meta.related) {
        if ((no_recursion && item in fields) || !no_recursion) {
          // 为了防止递归 无限循环, 只有指定的字段才会 做计算
          const [fld1, fld2] = meta.related.split('.')
          if (metadata[fld1].type === 'many2one' && rec[fld1]) {
            const refModel = this.env(metadata[fld1].relation)
            const ref = refModel.browse_one(rec[fld1], {
              fields: [fld2],
              no_recursion: 1
            })
            rec[item] = ref[fld2]
          } else {
            rec[item] = null
          }
        }
      } else if (meta.compute) {
        if ((no_recursion && item in fields) || !no_recursion) {
          // 为了防止递归 无限循环, 只有指定的字段才会 做计算
          if (this[meta.compute]) {
            const result = this[meta.compute](rec)
            rec[item] = result[item]
          } else {
            rec[item] = null
          }
        }
      } else if (meta.type === 'one2many') {
        // 这里将 o2m 作为计算列看待, 只处理 [ids]
        const o2m_domain = {}
        o2m_domain[meta.related_field] = rec.id
        const o2m_obj = this.env(meta.relation)
        const o2m_recs = o2m_obj.filter_by_domain({ domain2: o2m_domain })
        rec[item] = o2m_recs.map(o2m => o2m.id)
      } else if (meta.type === 'many2many') {
        // 这里将 m2m 作为计算列看待, 只处理 [ids]
        rec[item] = this.env(meta.rel_table)
          .records.filter(rel_item => rel_item[meta.id1] === rec.id)
          .map(rel_item => rel_item[meta.id2])
      } else {
        // records 中没定义的字段, 根据元数据 补充, 这里可以设置默认值
        const sss = rec[item]
        rec[item] = sss
      }
    })

    return rec
  }

  // 最后统一按照字段类型处理, 无论是计算列还是非计算列
  // date 字段格式化
  // selection 字段 补充 name
  // m2o, o2m, m2m 字段补充
  _update_value_for_type(fields = {}, rec0, no_recursion) {
    const rec = { ...rec0 }
    const metadata = this.metadata || {}
    Object.keys(metadata).forEach(item => {
      const meta = metadata[item]
      if (!meta) {
        //
      } else if (meta.type === 'date') {
        rec[item] = rec[item] ? parseTime(rec[item], '{y}-{m}-{d}') : rec[item]
      } else if (meta.type === 'selection') {
        const key_value = rec[item]
        rec[item] = key_value
        const new_values = meta.selection.filter(it => key_value === it[0])
        const new_value =
          new_values && new_values[0] ? new_values[0] : [key_value, key_value]
        rec[`${item}__name`] = new_value[1]
      } else if (meta.type === 'many2one') {
        const m2o_id = rec[item] || null
        if (!m2o_id) {
          rec[item] = m2o_id
          rec[`${item}__name`] = ''
          rec[`${item}__object`] = {}
        } else {
          if ((no_recursion && item in fields) || !no_recursion) {
            // 为了防止递归 无限循环, 只有指定的字段才会 做计算
            // console.log('xxx m2o, ', this.model)
            const ref = this.env(meta.relation).browse_one(m2o_id, {
              fields: ['name', 'display_name'],
              no_recursion: 1
            })
            rec[item] = m2o_id
            rec[`${item}__name`] = ref.display_name || ref.name
            rec[`${item}__object`] = ref
          }
        }
      } else if (meta.type === 'many2many' || meta.type === 'one2many') {
        if (rec[item] && rec[item].length) {
          const m2m_feilds = (fields || {})[item] || {}
          rec[`${item}__count`] = rec[item] ? rec[item].length : 0
          if ((no_recursion && item in fields) || !no_recursion) {
            // 为了防止递归 无限循环, 只有指定的字段才会 做计算
            const ref = this.env(meta.relation).browse(rec[item], {
              fields: { ...m2m_feilds, name: null, display_name: null },
              no_recursion: 1
            })

            rec[`${item}__objects`] = ref
            rec[`${item}__names`] = ref.map(item => item.display_name).join(',')
          }
        } else {
          // 如果没数 则不再查询了
          rec[item] = []
          rec[`${item}__objects`] = []
          rec[`${item}__count`] = 0
          rec[`${item}__names`] = ''
        }
      } else {
        // records 中没定义的字段, 根据元数据 补充, 这里可以设置默认值
        const sss = rec[item]
        rec[item] = sss
      }
    })

    return rec
  }

  _update_value(fields, rec0, no_recursion) {
    // console.log('update', this.model)
    let rec = { ...rec0 }
    rec = this._update_value_for_raw_fields(fields, rec)
    rec = this._update_value_for_compute(fields, rec, no_recursion)
    rec = this._update_value_for_type(fields, rec, no_recursion)
    // rec = this._update_value01(fields, rec)
    // rec = this._update_value02(fields, rec)

    if (!rec.display_name) {
      rec.display_name = rec.name || `${this.model},${rec.id}`
    }

    return rec
  }

  // 内部用
  fields_get(options) {
    // return fields_get(this, options)
    // const { allfields } = options
    return this.metadata
  }

  // 内部用, 支持 get_options 函数.
  // 处理 子表的字段的可选项
  _get_meta = field => {
    const metadata = this.fields_get()
    const fs = field.split('.')
    if (fs.length === 1) {
      return metadata[field]
    } else if (fs.length === 2) {
      const meta = metadata[fs[0]]
      if (['many2one', 'one2many', 'many2many'].includes(meta.type)) {
        const ref_metadata = this.env(meta.relation).fields_get()
        return ref_metadata[fs[1]]
      }
    }

    return { type: null }
  }

  // 内部用, 支持 get_options 函数, 取一个字段的可选项
  // TBD, 支持级联. 级联的返回值需要递归处理
  _get_option(field, options = {}) {
    const meta = this._get_meta(field)

    if (!meta) {
      return []
    } else if (meta.type === 'selection') {
      const res = meta.selection.map(item => {
        return { value: item[0], name: item[1] }
      })

      return res
    } else if (['many2one', 'many2many'].includes(meta.type)) {
      const { fields, cascader } = options
      const records = this.env(meta.relation).search_read2({
        ...options,
        fields: fields || { display_name: null }
      })

      if (!cascader) {
        return records
      }

      // TBD 2019-11-21, 根据 cascader 进行递归 处理
      // cascader: {
      //     value: 'id',
      //     label: 'display_name',
      //     children: {
      //         name: 'child_ids',
      //         cascader: {
      //             value: 'id',
      //             label: 'display_name'
      //         }
      //     }
      // }

      return records
    }
  }

  // 对外的函数. 获取 m2o, m2m, selection 字段的可选项
  // 同时取多个字段
  get_options(fields) {
    // console.log('xxxxx, get_options', this.model, fields)
    const options = Object.keys(fields).reduce((acc, fld) => {
      acc[fld] = this._get_option(fld, fields[fld])
      return acc
    }, {})
    return options
  }

  // 内部用的, 根据 id 取 一条记录
  browse_one(rid, options) {
    const records = this.browse(rid, options)
    return records && records.length ? records[0] : {}
  }

  // 对外的 read2 函数. 1 按照ids进行过滤. 2 处理计算列
  browse(rid, options = {}) {
    // console.log('browse', this.model, rid, options)
    const domain2 = { id: rid }

    const records = this.filter_by_domain({ domain2 })

    const { fields: fields0, no_recursion } = options
    let fields = fields0 || {}
    if (Array.isArray(fields)) {
      fields = fields.reduce((new_flds, fld) => {
        new_flds[fld] = null
        return new_flds
      }, {})
    }
    fields = Object.keys(fields).length
      ? fields
      : { name: null, display_name: null }

    return records.map(item => {
      const item2 = this._update_value(fields, item, no_recursion)
      return { ...item, ...item2 }
    })
  }

  // 仅仅被 res.users 的 authenticate 函数使用一次
  // 内部用的只查询一条记录
  search_one(options) {
    const records = this.search(options)
    return records && records.length ? records[0] : 0
  }

  // 仅仅被 search_one 使用一次
  // 内部自己用的查询函数, 1 处理计算列. 2 过滤.
  // 不排序和切片
  search(options) {
    const res = this._search(options)
    return res.map(item => item.id)
  }

  _search(options) {
    // console.log('xxxxx, _search,', this.model, options)
    // eslint-disable-next-line object-curly-spacing
    const { fields = {} } = options

    let res = this.records || []
    res = res.map(item => {
      const item2 = this._update_value(fields, item)
      return { ...item, ...item2 }
    })
    if (this.model === 'res.partner') {
      // console.log('xxxxx, saerch,', this.model, res)
    }

    return this.filter_by_domain(options, res)
  }

  // 对外用的 search_count2 函数, 1 处理计算列. 2 过滤. 3 取长度
  search_count(options) {
    // console.log('search_count, ', this.model, options)
    const res = this._search(options)
    return res.length
  }

  // 对外的 search_read2 查询函数
  // 1 处理计算列. 2 过滤. 3 排序, TBD, 目前只支持 id 排序
  // 4 offset. 5 limit
  search_read(options) {
    // console.log('search_read 1:', this.model, options)
    const { offset, limit, order } = options

    let res = this._search(options)

    const compare = function(property) {
      return function(a, b) {
        var value1 = a[property]
        var value2 = b[property]
        return value1 - value2
      }
    }

    res.sort(compare('id'))

    if (order === 'id desc') {
      res = res.reverse()
    }

    const offset2 = offset || 0
    const limit2 = limit || 1000000000

    res = res.filter(
      (item, index) => index < limit2 + offset2 && index >= offset2
    )
    // console.log('search_read 1:', this.model, res)

    return res
  }

  // 根据 domain 对数据进行过滤, 目前实现 like, in, =.
  // TBD, 需要扩展 >, >=, <, <=, !=, not in, child_of, parent_of
  filter_by_domain(options, records) {
    // return filter_by_domain(this, options, records)
    let mockList = [...(records || this.records || [])]

    // eslint-disable-next-line object-curly-spacing
    const { domain = {}, domain2 = {} } = options

    const domain_dict = { ...domain, ...domain2 }

    Object.keys(domain_dict).forEach(field0 => {
      const value = domain_dict[field0]

      const ss = field0.split('___')

      if (ss.length === 1) {
        ss.push(Array.isArray(value) ? 'in' : 'eq')
      }

      // TBD  filter: like, in , =

      const [field, op] = ss
      if (op === 'like') {
        // console.log('xxxx,like,', this.model, )
        if (value) {
          mockList = mockList.filter(item => item[field].includes(value))
        }
      } else if (op === 'in') {
        mockList = mockList.filter(item =>
          (Array.isArray(value) ? value : [value]).includes(item[field])
        )
      } else if (op === 'eq') {
        mockList = mockList.filter(item => item[field] === value)
      }
    })

    return mockList
  }

  // m2m 字段. 对中间表及对方表做了处理. 目前实现了, 0创建,4加关联,6去所有+加新关联.
  // m2m 字段. 1修改,2删除,3去关联,5去所有关联, 在创建中不能使用.
  // o2m 字段. TBD 为什么没实现?
  // o2m 字段. 目前对前端代码中, 头表单独创建, o2m子表通过修改头表进行管理
  create(vals) {
    // return create(this, values)
    const records = this.records
    // console.log('create2:', this.model, vals, records)

    const rid = records.length
      ? Math.max(...records.map(item => item.id)) + 1
      : 1
    const new_vals = { ...vals, id: rid }

    const metadata = this.fields_get()

    // m2m 字段 的 增删改
    // [0,0,{}] 创建
    // [1,1,{}] 修改, no used in create
    // [2,1] 删除ref, no used in create
    // [3,1] 删除联系, no used in create
    // [4,1] 增加
    // [5,] del all , no used in create
    // [6,0,[1,2]]  替换

    Object.keys(new_vals).forEach(item => {
      const meta = metadata[item]
      if (meta && meta.type === 'many2many') {
        const m2m = new_vals[item] || []
        const ref_m2m = this.env(meta.relation)
        let new_m2m = []

        m2m.forEach(ch => {
          const ch2 = [...ch]
          if (ch2.length === 1) {
            ch2.push(0)
            ch2.push(0)
          } else if (ch2.length === 2) {
            ch2.push(0)
          }
          const [op, p1, p2] = ch2
          if (op === 0) {
            const ch_new_vals = { ...p2 }
            const ch_id = ref_m2m.create(ch_new_vals)
            new_m2m.push(ch_id)
          } else if (op === 4) {
            new_m2m.push(p1)
          } else if (op === 6) {
            new_m2m = p2
          }
          const rel_records = this.env(meta.rel_table).records

          rel_records.splice(
            rel_records.findIndex(v => v[meta.id1] === rid),
            1
          )

          new_m2m.forEach(ii => {
            const new_ii = {}
            new_ii[meta.id1] = rid
            new_ii[meta.id2] = ii
            rel_records.push(new_ii)
          })
        })
      }

      const inverse = meta && meta.inverse
      if (inverse) {
        inverse(new_vals)
      }
    })

    records.push(new_vals)
    return rid
  }

  // o2m 字段, 对子表, 进行处理, 目前实现了 0创建,1修改,2删除.
  // o2m 字段. 3去关联-不需要实现, 4 加关联-不需要实现
  // o2m 字段. 5=3all,去所有关联-不需要实现, 6=5+4all 先去再加关联-不需要实现
  // m2m 字段. 对中间表及对方表做了处理. 目前实现了, 0创建,1修改,6去所有+加新关联.
  // m2m 字段. 3去关联=用6实现, 4加关联=用6实现, 5去所有关联=用6实现.
  write(rid, vals) {
    // console.log('write:', this.model, rid, vals)
    const records = this.records
    const rec = this.browse_one(rid)

    const new_vals = { ...vals }

    const metadata = this.fields_get()

    // m2m 字段 的 增删改
    // [0,0,{}] 创建
    // [1,1,{}] 修改
    // [2,1] 删除ref
    // [3,1] 删除联系
    // [4,1] 增加
    // [4,1] 增加
    // [5,] del all
    // [6,0,[1,2]]  替换
    Object.keys(new_vals).forEach(item => {
      const meta = metadata[item]
      if (meta && meta.type === 'many2many') {
        const m2m = new_vals[item] || []
        const ref_m2m = this.env(meta.relation)

        let new_m2m = rec[item] || []
        m2m.forEach(ch => {
          const ch2 = [...ch]
          if (ch2.length === 1) {
            ch2.push(0)
            ch2.push(0)
          } else if (ch2.length === 2) {
            ch2.push(0)
          }
          const [op, p1, p2] = ch2
          if (op === 0) {
            const ch_new_vals = { ...p2 }
            const ch_id = ref_m2m.create(ch_new_vals)
            new_m2m.push(ch_id)
          } else if (op === 1) {
            ref_m2m.write(p1, p2)
          } else if (op === 2) {
            ref_m2m.unlink(p1)
            new_m2m = new_m2m.filter(item => item !== p1)
          } else if (op === 6) {
            new_m2m = p2
          }
        })

        const rel_records = this.env(meta.rel_table).records

        let index2 = rel_records.findIndex(v => v[meta.id1] === rid)
        while (index2 >= 0) {
          rel_records.splice(index2, 1)
          index2 = rel_records.findIndex(v => v[meta.id1] === rid)
        }

        new_m2m.forEach(ii => {
          const new_ii = {}
          new_ii[meta.id1] = rid
          new_ii[meta.id2] = ii
          rel_records.push(new_ii)
        })
      } else if (meta && meta.type === 'one2many') {
        const o2m = new_vals[item] || []
        delete new_vals[item]

        const ref_o2m = this.env(meta.relation)

        o2m.forEach(ch => {
          const ch2 = [...ch]
          if (ch2.length === 2) {
            ch2.push(0)
          }
          const [op, p1, p2] = ch2

          if (op === 0) {
            const ch_new_vals = { ...p2 }
            ch_new_vals[meta.related_field] = rid
            ref_o2m.create(ch_new_vals)
          } else if (op === 1) {
            ref_o2m.write(p1, p2)
          } else if (op === 2) {
            ref_o2m.unlink(p1)
          }
        })
      }

      const inverse = meta && meta.inverse

      if (inverse) {
        this[inverse]({ id: rid, ...new_vals })
      }
    })

    records.forEach((item, index) => {
      if (item.id === rid) {
        records[index] = { ...records[index], ...new_vals }
        return true
      }
    })

    return true
  }

  // 直接切片 删除一条记录
  // m2m 字段 需要删除关系表的数据
  // TBD 其他表的 m2o 字段, 未做处理, 应该级联删除或置空或拒绝删除
  unlink(rid) {
    // console.log('unlink:', this.model, rid)
    Object.keys(this.Models).forEach(item => {
      const metadata = this.Models[item].metadata || {}
      Object.keys(metadata).forEach(item_meta => {
        const meta = metadata[item_meta] || {}
        if (meta.type === 'many2many' && meta.relation === this.model) {
          const rel_table = this.env(meta.rel_table).records
          rel_table.splice(
            rel_table.findIndex(v => v[meta.id2] === rid),
            1
          )
        }
      })
    })

    const records = this.records
    records.splice(
      records.findIndex(v => v.id === rid),
      1
    )
    return true
  }

  // 这几个带2的函数都是 odoorpc 对官方odoo的扩展
  // 在 mock 中, odoo官方的方法无效了. 直接实现了与带2函数一样的接口
  search_read2(options) {
    return this.search_read(options)
  }

  search_count2(options) {
    return this.search_count(options)
  }

  read2(rid, options) {
    return this.browse(rid, options)
  }

  create2(values) {
    return this.create(values)
  }

  write2(rid, values) {
    return this.write(rid, values)
  }
}

export default BaseModel

// // only used by _update_value0000
// // 为了防止 死循环, 单独做一个 只查询名字的函数
// // TBD display_name 可能是计算列, 需要做计算
// name_browse(rid) {
//   // return name_browse(this, rid)
//   const domain2 = { id: rid }

//   const records = this.filter_by_domain({ domain2 })
//   return records.map(item => {
//     return {
//       ...item,
//       display_name:
//         item.display_name || item.name || `${this.model},${item.id}`
//     }
//   })
// }

// // only used by _update_value0000
// // 内部用. 为了防止 死循环, 单独做一个 只查询名字的函数
// // TBD display_name 可能是计算列, 需要做计算
// name_browse_one(rid) {
//   const records = this.name_browse([rid])
//   const rec = records.length ? records[0] : {}
//   return rec
// }

// // selection, many2one, one2many, many2many
// _update_value02(fields0 = {}, rec0) {
//   const rec = { ...rec0 }
//   const metadata = this.metadata || {}
//   const fields = Object.keys(fields0).length
//     ? fields0
//     : { name: null, display_name: null }

//   return Object.keys(rec).reduce((new_rec, fld) => {
//     const meta = metadata[fld]
//     if (!meta) {
//       new_rec[fld] = rec[fld]
//       return new_rec
//     }
//     if (meta.type === 'date') {
//       new_rec[fld] = rec[fld] ? parseTime(rec[fld], '{y}-{m}-{d}') : rec[fld]
//     } else if (meta.type === 'selection') {
//       const key_value = rec[fld]
//       new_rec[fld] = key_value

//       const new_values = meta.selection.filter(item => key_value === item[0])
//       const new_value =
//         new_values && new_values[0] ? new_values[0] : [key_value, key_value]
//       new_rec[`${fld}__name`] = new_value[1]
//     } else if (meta.type === 'many2one') {
//       const m2o_id = rec[fld] || null
//       if (!m2o_id) {
//         new_rec[fld] = m2o_id
//         new_rec[`${fld}__name`] = ''
//         new_rec[`${fld}__object`] = {}
//       } else {
//         // console.log('xxx m2o, ', this.model)

//         const ref = this.env(meta.relation).name_browse_one(m2o_id)
//         new_rec[fld] = m2o_id
//         new_rec[`${fld}__name`] = ref.display_name || ref.display_name
//         new_rec[`${fld}__object`] = ref
//       }
//     } else if (meta.type === 'many2many' || meta.type === 'one2many') {
//       if (rec[fld] && rec[fld].length) {
//         const m2m_feilds = (fields || {})[fld] || {}
//         // console.log('xxx', this.model, fields, fld, m2m_feilds)
//         new_rec[fld] = rec[fld]
//         new_rec[`${fld}__count`] = rec[fld] ? rec[fld].length : 0

//         let ref = []

//         if (Object.keys(m2m_feilds).length) {
//           ref = this.env(meta.relation).browse(rec[fld], {
//             fields: { ...m2m_feilds, name: null, display_name: null }
//           })
//         } else {
//           ref = this.env(meta.relation).name_browse(rec[fld])
//         }

//         new_rec[fld] = rec[fld]
//         new_rec[`${fld}__objects`] = ref
//         new_rec[`${fld}__names`] = ref
//           .map(item => item.display_name)
//           .join(',')
//       } else {
//         // 如果没数 则不再查询了
//         new_rec[fld] = []
//         new_rec[`${fld}__objects`] = []
//         new_rec[`${fld}__count`] = 0
//         new_rec[`${fld}__names`] = ''
//       }
//     } else {
//       new_rec[fld] = rec[fld]
//     }
//     return new_rec
//   }, {})
// }

// // related, display,expression, one2many, many2many, compute
// // 从上到下 依次计算，可能有依赖关系
// // 因此元数据 metadata 中 的字段先后顺序不能乱
// _update_value01(fields0 = {}, rec0) {
//   const rec = { ...rec0 }
//   const metadata = this.metadata || {}

//   const fields = Object.keys(fields0).length
//     ? fields0
//     : { name: null, display_name: null }

//   Object.keys(metadata).forEach(item => {
//     const meta = metadata[item]
//     if (!meta) {
//       //
//     } else if (meta.display) {
//       rec[item] = get_display_name(rec, meta.display)
//     } else if (meta.expression) {
//       rec[item] = get_expression_value(rec, meta.expression)
//     } else if (meta.related) {
//       const [fld1, fld2] = meta.related.split('.')
//       if (metadata[fld1].type === 'many2one' && rec[fld1]) {
//         const refModel = this.env(metadata[fld1].relation)
//         const ref = refModel.browse_one(rec[fld1])
//         rec[item] = ref[fld2]
//       } else {
//         rec[item] = null
//       }
//     } else if (meta.compute) {
//       if (item in fields) {
//         if (this[meta.compute]) {
//           const result = this[meta.compute](rec)
//           rec[item] = result[item]
//         } else {
//           rec[item] = null
//         }
//       }
//     } else if (meta.type === 'one2many') {
//       const o2m_domain = {}
//       o2m_domain[meta.related_field] = rec.id
//       const o2m_obj = this.env(meta.relation)
//       const o2m_recs = o2m_obj.filter_by_domain({ domain2: o2m_domain })
//       rec[item] = o2m_recs.map(o2m => o2m.id)
//     } else if (meta.type === 'many2many') {
//       rec[item] = this.env(meta.rel_table)
//         .records.filter(rel_item => rel_item[meta.id1] === rec.id)
//         .map(rel_item => rel_item[meta.id2])
//     } else {
//       // 忘记 为什么 这么处理了
//       const sss = rec[item]
//       rec[item] = sss
//     }
//   })

//   if (!rec.display_name) {
//     rec.display_name = rec.name || `${this.model},${rec.id}`
//   }

//   return rec
// }

// // TBD 彻底解决递归问题
// _update_value2(fields, rec0) {
//   let rec = { ...rec0 }

//   // console.log('update', rec)
//   rec = this._update_value01(fields, rec)
//   // console.log('update', rec)
//   rec = this._update_value02(fields, rec)
//   return rec
// }
